import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { FindOperator, Like, Repository } from 'typeorm';

import { User } from './entities/user.entity';
import { Role } from './entities/role.entity';
import { Permission } from './entities/permission.entity';

import { encryptPassword } from '../utils/utils';

import { UpdateUserDto } from './dto/update-user.dto';
import { UserDetailVo } from './vo/detail.vo';
import { ListUserDto } from './dto/list-user.dto';

@Injectable()
export class UserService {
  constructor() {}

  @InjectRepository(User)
  private userRepository: Repository<User>;

  @InjectRepository(Role)
  private roleRepository: Repository<Role>;

  @InjectRepository(Permission)
  private permissionRepository: Repository<Permission>;

  async getUserList(query: ListUserDto) {
    const condition: Record<string, FindOperator<string>> = {};

    const fields = ['username', 'nickname', 'email'];
    fields.forEach((field) => {
      const value = query[field as keyof ListUserDto];
      if (value) {
        condition[field] = Like(`%${value}%`);
      }
    });

    const [list, total] = await this.userRepository.findAndCount({
      skip: (query.page - 1) * query.limit,
      take: query.limit,
      where: {
        isFrozen: false,
        ...condition,
      },
    });
    return {
      list,
      total,
    };
  }

  async updatePassword(id: number, password: string) {
    const checkUser = await this.checkUserExistis(id);
    if (checkUser) return checkUser;

    const { salt, hash } = encryptPassword(password);
    await this.userRepository.update(id, {
      password: hash,
      salt: salt,
    });
    return {
      code: 200,
      msg: '修改成功',
    };
  }

  async deleteUser(id: number) {
    const checkUser = await this.checkUserExistis(id);
    if (checkUser) return checkUser;

    await this.userRepository.update(id, {
      isFrozen: true,
    });
    return {
      code: 200,
      msg: '删除成功',
    };
  }

  async initData() {
    // admin 是 管理员 能够访问 ccc 和 ddd接口
    // list 是普通用户 能够访问 ddd接口
    const user = new User();
    user.username = 'admin';
    user.nickname = '管理员';
    const { hash, salt } = encryptPassword('123456');
    user.password = hash;
    user.salt = salt;
    user.email = 'sorry00asd@gmail.com';
    user.isAdmin = true;
    user.phone = '13111111111';

    const user2 = new User();
    user2.username = 'lisa';
    user2.nickname = '丽莎';
    const { hash: hash2, salt: salt2 } = encryptPassword('123456');
    user2.password = hash2;
    user2.salt = salt2;
    user2.email = 'lisa@gmail.com';
    user2.phone = '13222222222';

    const role = new Role();
    role.name = '管理员';

    const role2 = new Role();
    role2.name = '普通用户';

    const permission = new Permission();
    permission.code = 'ccc';
    permission.description = '访问ccc接口';

    const permission2 = new Permission();
    permission2.code = 'ddd';
    permission2.description = '访问ddd接口';

    user.roles = [role];
    user2.roles = [role2];

    role.permissions = [permission, permission2];
    role2.permissions = [permission2];

    await this.permissionRepository.save([permission, permission2]);
    await this.roleRepository.save([role, role2]);
    await this.userRepository.save([user, user2]);
  }

  async updateUser(updateUserDto: UpdateUserDto) {
    const checkUser = await this.checkUserExistis(updateUserDto.id);
    if (checkUser) return checkUser;

    await this.userRepository.update(updateUserDto.id, updateUserDto);
    return {
      msg: '更新成功',
    };
  }

  async getUserDetail(id: number): Promise<UserDetailVo> {
    const user = await this.userRepository.findOne({
      where: { id, isFrozen: false },
    });
    if (!user) {
      throw new NotFoundException('用户不存在');
    }
    const vo = new UserDetailVo();

    vo.id = user.id;
    vo.username = user.username;
    vo.nickname = user.nickname;
    vo.email = user.email;
    vo.avatar = user.avatar;
    vo.phone = user.phone;
    vo.createdAt = user.createdAt;

    return vo;
  }

  private async checkUserExistis(id: number) {
    const existUser = await this.userRepository.findOne({
      where: { id, isFrozen: false },
    });
    if (!existUser) {
      throw new NotFoundException('用户不存在');
    }
    return null;
  }
}
